#!/home/python/.virtualenvs/equity/bin/python

import sys
sys.path.append('./')
sys.path.insert(0, "../")

import os
if not os.getenv('DJANGO_SETTINGS_MODULE'):
    os.environ['DJANGO_SETTINGS_MODULE'] = 'equity_mall.settings.prod'

import django
django.setup()


import requests, datetime, uuid, hashlib, json
from gmssl import sm2


class Schengle():

    def __init__(self):

        self.source = "GDYZQY"
        '''测试环境'''
        # self.app_id = "6aaa0234375d4a2ba371dd87ae1761971729044906169"
        # self.sign_secret = "FGOhEdso1a7S5/hKAm2p8afwwHBbrbQnjiKm0mLXq3c="
        # private_key = "16e51e5eefe448b8a78b1bc23ad98e9ea36da8e7c0ebba6bc092a8a88399690d"
        # public_key = "04ea0911fa36f3288441a12060a66147fb6360677e48ed0efe51bdfad4406d43d4697b091d718d108012c2d833e7867784ee55cda0ed986322b85b22c22ed12d2b"
        '''正式环境'''
        self.app_id = "67e860566a5c44f8a863f747af94e3781731057812916"
        self.sign_secret = "jApfKOIImz9EcHTucwHh0wav2DhCBJKjmas//HJZ/w4="
        private_key = "f6b95e111d0739e334b0eefeddf5d364acf1988924222bf4cdbc613fca81865c"
        public_key = "93AEC88E616F973B6A89A413F759E84FAD339FC739C478E0C44BC1E705275332A82A6B0050EE31CC0FA816E1E4B306739AFA1CA0F96BA712BFF7E7050FDE6E8F"
        self.sm2_crypt = sm2.CryptSM2(public_key=public_key, private_key=private_key, mode=1)
        self.base_url = "https://api.schengle.com/gateway"
        # self.base_url = "https://api-test.schengle.com/gateway"

    @property
    def __timestamp(self) -> str:
        """获取时间戳(%Y-%m-%d %H:%M:%S格式)"""
        return datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")

    @property
    def __request_id(self) -> str:
        """获取请求id（uuid4）"""
        return uuid.uuid4().hex

    def __sign(self, params: dict) -> str:
        """
        生成签名
        :param params: 接口参数
        :return: 签名
        """
        if not params:
            return ""
        # 按照键排序
        sorted_params = sorted(params.items())
        sb = []
        for key, value in sorted_params:
            if key == "sign" or not value:
                continue
            sb.append(f"{key.strip()}={value.strip()}&")
        # 拼接字符串并进行 MD5 加密
        sb.append(f"key={self.sign_secret}")
        sign_content = ''.join(sb)
        # 计算 MD5 加密并返回大写结果
        return hashlib.md5(sign_content.encode('utf-8')).hexdigest().upper()

    def __encryption_data(self, prams) -> str:
        """
        接口数据加密(sm2 加密)
        :param prams: 接口参数
        :return: 加密后的数据
        """
        json_prams = json.dumps(prams, sort_keys=True).replace(" ", "")
        encode_info = self.sm2_crypt.encrypt(json_prams.encode(encoding="utf-8"))
        return encode_info.hex()

    def __verify_sign(self, response_data: dict) -> bool:
        """
        验证响应签名
        :param response_data: 响应数据
        :return: bool 结果
        """
        # 删除签名
        response_sign = response_data.pop("sign")
        # 生成签名
        sign = self.__sign(response_data)
        if response_sign == sign:
            return True
        return False

    def __decrypt_date(self, encrypted_data) -> dict:
        """
        解密响应的数据
        :param encrypted_data:
        :return:
        """
        if encrypted_data[:2] == "04":
            encrypted_data = encrypted_data[2:]
        encrypted_data = bytes.fromhex(encrypted_data)
        decrypted_data = self.sm2_crypt.decrypt(encrypted_data)
        return json.loads(decrypted_data.decode())

    def __request_data(self, method: str, params: dict) -> dict:
        """
        生成请求数据(公共参数、接口加密数据、签名)
        :param method: 请求方法
        :param params: 接口参数
        :return: 请求的数据
        """
        # 加密接口数据
        bizContent = self.__encryption_data(params)
        request_data = {
            "method": method,
            "requestId": self.__request_id,
            "appId": self.app_id,
            "bizContent": bizContent,
            "signType": "md5",
            "version": "1.0",
            "timestamp": self.__timestamp
        }
        request_data["sign"] = self.__sign(request_data)
        return request_data

    def __request_post(self, method: str, params: dict, is_add_source=False) -> dict:
        """
        请求接口(请求接口、验签、解密数据)
        :param method: 请求方法
        :param params: 接口数据
        :return: 响应数据
        """
        # 如果需要添加机构编号则添加
        if is_add_source:
            params['source'] = self.source
        # 生成请求数据(公共参数、签名、数据加密)
        request_data = self.__request_data(method, params)
        # 请求
        response = requests.post(self.base_url, json=request_data)
        response_data = response.json()
        # if response_data["code"] != "0000":
        #     raise ValueError("盛大系统异常，联系盛大工作人员！")
        # if not self.__verify_sign(response_data):
        #     raise ValueError("接口响应签名错误, 忽略处理!")
        result_data = self.__decrypt_date(response_data['data'])
        # if result_data["resultCode"] != "success":
        #     raise ValueError(f"盛大提示:{result_data['resultDesc']}")
        return result_data

    @staticmethod
    def __verify_required_params(params: dict, required_keys: list):
        """
        验证必填参数
        :param params: 接口传入参数
        :param required_keys: 必填的key
        :return:
        """
        lack_keys = list(set(required_keys) - set(params.keys()))
        if lack_keys:
            raise ValueError(f"缺少必要参数: {lack_keys}")

    @staticmethod
    def __verify_list_time_required_key(params: dict, key: str, required_keys: list, allow_null=False):
        """
        验证数据下面的
        :param params: 接口传入参数
        :param key: 获取参数的key
        :param required_keys: 必须的key
        :param allow_null: 必须的key
        :return:
        """
        values = params.get(key)
        if not values and not allow_null:
            raise ValueError(f"[{key}]参数不允许为空")
        for index, item in enumerate(values):
            lack_keys = list(set(required_keys) - set(item.keys()))
            if lack_keys:
                raise ValueError(f"[{key}]参数下标位{index}的原始缺少必要key: {lack_keys}")

    def create_order(self, params: dict) -> dict:
        """
        统一下单
        :param params: 接口参数
        :return: 响应的订单数据
        """
        # 验证参数
        required_keys = ["source", "outTradeNo", "formCode", "username"]
        self.__verify_required_params(params, required_keys)
        # 请求接口
        method = "sd.order.h5.create"
        return self.__request_post(method, params, is_add_source=True)

    def query_order(self, params: dict) -> dict:
        """
        产品订单查询
        :param params: 接口参数
        :return: 响应的订单数据
        """
        # 验证参数
        if not any([params.get("orderId"), params.get("outTradeNo")]):
            raise ValueError("参数[orderId、outTradeNo]必填一个")

        # 请求接口
        method = "sd.order.h5.query"
        return self.__request_post(method, params, is_add_source=True)

    def cancel_order(self, params: dict) -> dict:
        """
        产品订单查询
        :param params: 接口参数
        :return: 响应的订单数据
        """
        # 验证参数
        if not any([params.get("orderId"), params.get("outTradeNo")]):
            raise ValueError("参数[orderId、outTradeNo]必填一个")

        # 请求接口
        method = "sd.order.h5.cancel"
        return self.__request_post(method, params, is_add_source=True)

    def notify_order(self, params: dict) -> dict:
        """
        订单状态通知回调
        :param params: 接口参数
        :return: 响应的订单数据
        """
        # 验证参数
        required_keys = ["orderId", "status", "formCode", "serviceId", "username", "phone", "createTime", "couponId"]
        self.__verify_required_params(params, required_keys)
        if params.get("status") not in ["0", "1", "2", "3", "4", "5", "6", "0", "303", "304", "305", "306", "602", "603"]:
            raise ValueError("参数 [status] 值错误")

        # 请求接口
        method = "sd.order.h5.notify"
        return self.__request_post(method, params, is_add_source=True)

    def grant_coupon(self, params: dict) -> dict:
        """
        发券
        :param params: 接口参数
        :return: 响应的订单数据
        """
        # 验证参数
        required_keys = ["couponGrantInfoList"]
        self.__verify_required_params(params, required_keys)
        self.__verify_list_time_required_key(params, "couponGrantInfoList", ["couponId"])

        # 请求接口
        method = "sd.order.coupon.grant"
        return self.__request_post(method, params, is_add_source=True)


schengle = Schengle()


if __name__ == '__main__':
    pass
    # 查询订单
    # result = schengle.query_order({"outTradeNo": "GDYZQY524734447302574080"})
    result = schengle.query_order({"outTradeNo": "2024161308413659"})
    # result = schengle.sm2_crypt.encrypt(json.dumps({"resultCode": "success", "resultDesc": "", "data": ""}).encode()).hex()
    print(result)